#include<iostream>
#include "../source/config.h"
#include "../source/log.h"
#include <yaml-cpp/yaml.h>

#include <string>
#include <vector>
using namespace std;

#ifdef aaa
framework::ConfigVar<int>::ptr int_value_config = 
    framework::Config::Lookup("system.port", (int)8080, "system port");

// framework::ConfigVar<double>::ptr int_valueError_config = 
//     framework::Config::Lookup("system.port", (double)8080, "system port");

framework::ConfigVar<float>::ptr float_value_config = 
    framework::Config::Lookup("system.value", (float)3.14f, "test num");

framework::ConfigVar<std::vector<int> >::ptr g_int_vec_value_config =
    framework::Config::Lookup("system.int_vec", std::vector<int>{1, 2}, "system int vec");

framework::ConfigVar<std::list<double> >::ptr g_double_list_value_config =
    framework::Config::Lookup("system.double_list", std::list<double>{3.14, 2.75}, "system double list");

framework::ConfigVar<std::set<int> >::ptr g_int_set_value_config =
    framework::Config::Lookup("system.int_set", std::set<int>{3, 2}, "system int set");

framework::ConfigVar<std::unordered_set<int> >::ptr g_int_uset_value_config =
    framework::Config::Lookup("system.int_uset", std::unordered_set<int>{4, 6}, "system int uset");

framework::ConfigVar<std::map<std::string, int> >::ptr g_int_map_value_config =
    framework::Config::Lookup("system.str_int_map", std::map<std::string, int>{{"key1",2}}, "system str int map");

framework::ConfigVar<std::unordered_map<std::string, int> >::ptr g_int_umap_value_config =
    framework::Config::Lookup("system.str_int_umap", std::unordered_map<std::string, int>{{"key1",2}}, "system str int umap");

//打印yml文件
void print_yaml(const YAML::Node& node, int level) 
{
    if(node.IsScalar()) 
    {
        std::cout << std::string(level * 4, ' ')
            << node.Scalar() << " - " << node.Type() << " - " << level << "   --- IsScalar" << std::endl;
    }
    else if(node.IsNull()) 
    {
        std::cout << std::string(level * 4, ' ')
            << "NULL - " << node.Type() << " - " << level << std::endl;;
    }
    else if(node.IsMap()) 
    {
        for(auto it = node.begin();it != node.end(); ++it)
        {
            std::cout << std::string(level * 4, ' ')
                    << it->first << " - " << it->second.Type() << " - " << level << "   --- IsMap" << std::endl;
            print_yaml(it->second, level + 1);
        }
    } 
    else if(node.IsSequence()) 
    {
        for(size_t i = 0; i < node.size(); ++i) 
        {
            std::cout << std::string(level * 4, ' ')
                << i << " - " << node[i].Type() << " - " << level <<  "   --- IsSequence" << std::endl;
            print_yaml(node[i], level + 1);
        }
    }
}

//测试STL型与配置文件中的数据转换
void test_yaml()
{

#define XX(g_var, name, prefix) \
    { \
        auto var = g_var->getValue(); \
        for(const auto &t: var) \
        { \
            std::cout << #prefix << "   " << #name << ": " << t << std::endl; \
        } \
        std::cout << #prefix << "    " << #name  << ": " << std::endl << g_var->toString() << std::endl; \
    }

#define XX_M(g_var, name, prefix) \
    { \
        auto var = g_var->getValue(); \
        for(const auto &t: var) \
        { \
            std::cout << #prefix << "   " << #name << ": " << t.first << " -- " << t.second << std::endl; \
        } \
        std::cout << #prefix << "    " << #name  << ": " << std::endl << g_var->toString() << std::endl; \
    }

    XX(g_int_vec_value_config, int_vec, befor);
    XX(g_double_list_value_config, double_list, befor);
    XX(g_int_set_value_config, int_set, befor);
    XX(g_int_uset_value_config, int_uset, befor);
    XX_M(g_int_map_value_config, str_int_map, befor);
    XX_M(g_int_umap_value_config, str_int_map, befor);
    cout << "======================================================" << endl;

    //打开.yml文件
    YAML::Node root = YAML::LoadFile("./config/log.yml");
    //将yml文件中的值写入ConfigVar中
    framework::Config::LoadFromYaml(root);

    XX(g_int_vec_value_config, int_vec, after);
    XX(g_double_list_value_config, double_list, after);
    XX(g_int_set_value_config, int_set, after);
    XX(g_int_uset_value_config, int_uset, after);
    XX_M(g_int_map_value_config, str_int_map, after);
    XX_M(g_int_umap_value_config, str_int_map, after);
}

class Person
{
public:
    Person(std::string name = "lalala", int age = 10, bool sex = true):m_name(name), m_age(age), m_sex(sex) {}

    std::string toString() const
    {
        std::stringstream ss;
        ss << "Persion name = " << m_name
           << "  age = " << m_age
           << "  sex = " << m_sex;
        return ss.str();
    }

    bool operator==(const Person& p) const
    {
        return p.m_age == this->m_age
            && p.m_name == this->m_name
            && p.m_sex == this->m_sex;
    }

    std::string m_name;
    int m_age;
    bool m_sex;
};


namespace framework
{
    //string 转为 Person 
    template<>
    class LexicalCast<std::string, Person>
    {
    public:
        Person operator()(const std::string & str)
        {
            YAML::Node node = YAML::Load(str);
            Person p;
            p.m_name = node["name"].as<std::string>();
            p.m_age = node["age"].as<int>();
            p.m_sex = node["sex"].as<bool>();
            return p;
        }
    };

    template<>
    class LexicalCast<Person, std::string>
    {
    public:
        std::string operator()(const Person& p)
        {
            YAML::Node node;
            node["name"] = p.m_name;
            node["age"]  = p.m_age;
            node["sex"]  = p.m_sex;
            
            std::stringstream ss;
            ss << node;
            return ss.str();
        }
    };
}


framework::ConfigVar<Person>::ptr g_person = 
    framework::Config::Lookup("class.person", Person(), "system persoon");

framework::ConfigVar<std::map<std::string, Person>>::ptr g_person_map = 
    framework::Config::Lookup("class.map", map<std::string, Person>(), "system persoon map");

framework::ConfigVar<std::map<std::string, std::vector<Person> > >::ptr g_person_vec_map = 
    framework::Config::Lookup("class.vec_map", map<std::string, std::vector<Person> >(), "system persoon map");

//测试自定义类型与配置文件中的数据转换
void test_class()
{
#define XX_P_MAP(g_var, name, prefix) \
{ \
    auto m = g_var->getValue(); \
    for(const auto &t : m) \
    { \
        cout << #prefix << "  " << #name << "  " << t.first << "  --  " << t.second.toString() << std::endl; \
    }\
}

    //注册回调函数
    g_person->addListener(10, [](const Person& oldValue, const Person& newValue){
        std::cout << "old_value: " << oldValue.toString() << "\tnew_value: " << newValue.toString() << std::endl;
    });

    std::cout << "befor: " << g_person->getValue().toString() << " - " << std::endl << g_person->toString() << std::endl;
    XX_P_MAP(g_person_map, class.map, befor);
    std::cout << "befor: " << g_person_vec_map->toString();

    YAML::Node root = YAML::LoadFile("./config/test.yml");
    framework::Config::LoadFromYaml(root);
    cout << "======================================================" << endl;

    std::cout << "after: " << g_person->getValue().toString() << " - " <<  std::endl << g_person->toString() << std::endl;
    XX_P_MAP(g_person_map, class.map, last);
    std::cout << "after: " << g_person_vec_map->toString();
}

#endif

void test_log() 
{
    static framework::Logger::ptr system_log = FRAMEWORK_LOG_NAME("system");
    FRAMEWORK_LOG_INFO(system_log) << "hello system" << std::endl;
    std::cout << framework::LoggerMgr::GetInstance()->toYamlString() << std::endl;
    YAML::Node root = YAML::LoadFile("./config/log.yml");
    framework::Config::LoadFromYaml(root);
    std::cout << "=============" << std::endl;
    std::cout << framework::LoggerMgr::GetInstance()->toYamlString() << std::endl;
    std::cout << "=============" << std::endl;
    std::cout << root << std::endl;
    FRAMEWORK_LOG_INFO(system_log) << "hello system" << std::endl;

    system_log->setFormatter("%d - %m%n");
    FRAMEWORK_LOG_INFO(system_log) << "hello system" << std::endl;
} 

int main(void)
{
    // YAML::Node root = YAML::LoadFile("./config/test.yml");
    // std::cout << root << std::endl;
    // cout << "======================================================" << endl;
    // print_yaml(root, 0);
    // test_yaml();
    //test_class();

    test_log();
    
    framework::Config::Visit([](framework::ConfigVarBase::ptr var){
    cout << "+++++++++++++++++++++++++++++++++++++++++++++++++++" << endl
         << "name = " << var->getName() << endl
         << "description = " << var->getDescription() << endl
         << "typename = " << var->getTypeName() << endl
         << "value = " << var->toString() << endl
         << "+++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;
    });

    return 0;
}

